package net.ufrog.common;

import net.ufrog.common.app.App;
import net.ufrog.common.utils.Strings;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 线程池工具
 *
 * @author ultrafrog, ufrog.net@gmail.com
 * @version 0.1, 2017-01-19
 * @since 0.1
 */
public class ThreadPools {

    private static final String DEFAULT_EXECUTOR    = "default";

    private static final String PROPERTY_TYPE       = "type";
    private static final String PROPERTY_SIZE       = "size";

    private static final int TYPE_CACHED            = 0;
    private static final int TYPE_FIXED             = 1;
    private static final int TYPE_SINGLE            = 2;
    private static final int TYPE_SCHEDULED         = 3;

    private static Map<String, ExecutorService> mExecutorService = new HashMap<>();
    private static Map<String, Integer> mType = new HashMap<>();

    static {
        mType.put("cached", TYPE_CACHED);
        mType.put("fixed", TYPE_FIXED);
        mType.put("single", TYPE_SINGLE);
        mType.put("scheduled", TYPE_SCHEDULED);
    }

    /** 构造函数 */
    private ThreadPools() {}

    /**
     * @param command 执行指令
     */
    public static void execute(Runnable command) {
        execute(command, DEFAULT_EXECUTOR);
    }

    /**
     * @param command 执行指令
     * @param key 键值
     */
    public static void execute(Runnable command, String key) {
        getThreadPool(key).execute(command);
    }

    /**
     * @param command 执行指令
     * @param key 键值
     * @param delay 延迟
     * @param timeUnit 时间单位
     */
    public static void schedule(Runnable command, String key, Long delay, TimeUnit timeUnit) {
        getScheduledThreadPool(key).schedule(command, delay, timeUnit);
    }

    /**
     * @param key 键值
     * @return 线程池
     */
    public static ExecutorService getThreadPool(String key) {
        if (!mExecutorService.containsKey(key)) {
            mExecutorService.put(key, newThreadPool(getConfig(key, PROPERTY_TYPE), key));
        }
        return mExecutorService.get(key);
    }

    /**
     * @param key 键值
     * @return 计划线程池
     */
    public static ScheduledExecutorService getScheduledThreadPool(String key) {
        return (ScheduledExecutorService) getThreadPool(key);
    }

    /**
     * @param key 键值
     * @param property 属性
     * @return 参数值
     */
    private static String getConfig(String key, String property) {
        return getConfig(key, property, null);
    }

    /**
     * @param key 键值
     * @param property 属性
     * @param defaultValue 默认值
     * @return 参数值
     */
    private static String getConfig(String key, String property, String defaultValue) {
        String code = String.format("thread.pool.%s.%s", key, property);
        return App.config(code, defaultValue);
    }

    /**
     * @param type 类型
     * @param key 键值
     * @return 线程池
     */
    private static ExecutorService newThreadPool(String type, String key) {
        if (!Strings.empty(type)) {
            switch (mType.get(type)) {
                case TYPE_FIXED:
                    return Executors.newFixedThreadPool(Integer.valueOf(getConfig(key, PROPERTY_SIZE, "5")));
                case TYPE_SINGLE:
                    return Executors.newSingleThreadExecutor();
                case TYPE_SCHEDULED:
                    return Executors.newScheduledThreadPool(Integer.valueOf(getConfig(key, PROPERTY_SIZE, "5")));
            }
        }
        return Executors.newCachedThreadPool();
    }
}
